use tracing::debug;

use crate::{
    ast_define::{
        MetaInfo, Program,
        declear::{ConstDecl, ConstDef, Decl, VarDef},
        function::{FuncDef, FuncFParams, FuncType},
        general::CompUnit,
        literal::Ident,
    },
    semantic_analysis::{SemanticError, Symbol, SymbolType, Type, symbol_table::ScopeType},
};

impl super::TypeChecker {
    // 线性分析, 防止在后面的全局符号被前面的函数体使用
    pub fn analyze_program(&mut self, program: &Program) -> Result<(), Vec<SemanticError>> {
        for comp_unit in &program.comp_units {
            match comp_unit {
                CompUnit::Decl(decl) => {
                    self.analyze_global_decl(decl);
                }
                CompUnit::FuncDef(func_def) => {
                    self.analyze_func_def(func_def);
                }
            }
        }
        eprint!("\n全局符号表:\n{:#?}", self.symbol_table);
        match self.errors.is_empty() {
            true => Ok(()),
            false => Err(std::mem::take(&mut self.errors)),
        }
    }

    /// 收集全局变量声明
    pub fn analyze_global_decl(&mut self, decl: &Decl) {
        match decl {
            Decl::ConstDecl(const_decl) => {
                // ! 测试中保证const定义仅有一个const int 数组
                self.analyze_global_const_def(const_decl);
            }
            Decl::VarDecl(var_decl) => {
                for var_def in &var_decl.var_def {
                    self.analyze_global_var_def(var_def);
                }
            }
        }
    }

    /// 分享与收集全局常量定义
    pub fn analyze_global_const_def(&mut self, const_decl: &ConstDecl) {
        // 1. 由于测试样例中仅有一处const int数组定义(还是一维的)
        // 所以这里就不用考虑非数组的情况了
        let global_const_var_type = Type::Array(1);
        let global_const_def = &const_decl.const_def;

        // 2. lab3中保证数组定义的有效性, 所以这里不需要检查了
        let symbol = Symbol::new(
            global_const_def.ident.value.clone(),
            SymbolType::Constant(global_const_var_type),
            global_const_def.ident.meta_info.clone(),
        );
        // 由于测试样例中仅有一处const int数组定义,
        // 所以这里就不用检查重复定义了
        self.symbol_table.define(symbol);
    }

    /// 收集变量定义
    pub fn analyze_global_var_def(&mut self, var_def: &VarDef) {
        // 1. 测试样例中的全局变量都是仅有一处是声明的同时定义的
        // 并且是合法的, 所以就不用检查了
        let (ident, const_exp) = match var_def {
            VarDef::Ident_ConstExp_Brackets_Wrapper_Assign_InitVal(def) => {
                (&def.ident, &def.const_exp)
            }
            VarDef::Ident_ConstExp_Brackets_Wrapper(def) => (&def.ident, &def.const_exp),
        };
        let global_var_type = match const_exp.is_empty() {
            // 构造数组类型，这里由于lab3中明确提到了简化处理
            // 所以这里只记录纬度
            false => Type::Array(const_exp.len()),
            true => Type::Int,
        };
        // 因为只声明, 不定义, 所以这里就不用检查赋值的问题了
        let symbol = Symbol::new(
            ident.value.clone(),
            SymbolType::Variable(global_var_type.clone()),
            ident.meta_info.clone(),
        );
        match self
            .symbol_table
            .check_redefine(&symbol.name, &symbol.symbol_type)
            .is_err()
        {
            true => {
                self.errors.push(SemanticError::redefined_variable(
                    &symbol.name,
                    symbol.location.clone(),
                ));
            }
            false => self.symbol_table.define(symbol),
        }
    }

    pub fn analyze_func_def(
        &mut self,
        FuncDef {
            func_type,
            ident: Ident {
                value: ident,
                meta_info,
            },
            func_f_params,
            block_items,
            ..
        }: &FuncDef,
    ) {
        // 1. 获取函数类型
        let return_type = match &func_type {
            FuncType::INT(_) => Type::Int,
            FuncType::VOID(_) => Type::Void,
        };

        // 2. 检查命名冲突
        if self
            .symbol_table
            .check_redefine(ident, &SymbolType::Function(return_type.clone()))
            .is_err()
        {
            return self
                .errors
                .push(SemanticError::redefined_function(ident, meta_info.clone()));
        }

        // 构建全局函数符号
        // 因为函数有可能被递归调用,
        // 所以需要先分析函数参数, 构建全局函数符号
        let defined_params =
            self.build_global_func_symbol(ident, &return_type, func_f_params, meta_info);

        // 3. 分析函数
        // 设置当前函数返回类型(用于检查return语句)
        self.current_function_return_type = Some(return_type.clone());
        // 进入函数作用域
        self.symbol_table
            .enter_scope(ScopeType::Function(ident.clone()));
        // 在函数作用域中注册函数参数
        for param in defined_params {
            self.symbol_table.define(param);
        }
        // 检查函数体
        for block_item in block_items {
            self.check_block_item(block_item);
        }

        // 退出函数作用域
        self.symbol_table.exit_scope();
        self.current_function_return_type = None;
    }

    pub fn build_global_func_symbol(
        &mut self,
        func_name: &str,
        return_type: &Type,
        params: &Option<FuncFParams>,
        meta_info: &MetaInfo,
    ) -> Vec<Symbol> {
        // 函数参数对外提供`顺序和类型`, 对内提供符号即`名称与类型`
        // 函数参数应该是个数组, 以保证其有序性
        let mut assist_map = std::collections::HashSet::new();
        let mut defined_params = vec![];

        if let Some(params) = params {
            for param in &params.func_f_params {
                // 构建符号以对外提供`顺序和类型`
                let param_type = match &param.brackets_and_exp {
                    // `lab3要求.md`中保证测试用例中的函数参数不会为二维及以上的数组
                    Some(_) => Type::Array(1),
                    None => Type::Int,
                };

                // 检查参数名是否重复
                if assist_map.contains(&param.ident.value) {
                    // 报告重复定义错误
                    self.errors.push(SemanticError::redefined_variable(
                        &param.ident.value,
                        param.ident.meta_info.clone(),
                    ));
                    // 跳过重复的参数，不添加到符号表中（错误恢复）
                    continue;
                }

                assist_map.insert(param.ident.value.clone());
                defined_params.push(Symbol::new(
                    param.ident.value.clone(),
                    SymbolType::Variable(param_type),
                    param.ident.meta_info.clone(),
                ));
            }
        }
        // 构建全局函数符号
        let symbol = Symbol::new(
            func_name.to_string(),
            SymbolType::Function(Type::Function {
                params: defined_params.clone(),
                return_type: Box::new(return_type.clone()),
            }),
            meta_info.clone(),
        );
        self.symbol_table.define(symbol);

        defined_params
    }
}
